﻿''' <summary>
''' A simple attribute to help organize cascading property changed events. Properties that are dependent on other
''' properties for their values can apply this attribute. The Property Changed handler can then look up dependent
''' properties and subsequently raise their property changed events.
''' </summary>
''' <remarks>jdb 4/14/2011</remarks>
<AttributeUsage(AttributeTargets.Property, AllowMultiple:=True)>
Public Class PropertyDependencyAttribute
    Inherits Attribute

    Private _dependentOnPropertyName As String
    Public Property DependentOnPropertyName() As String
        Get
            Return _dependentOnPropertyName
        End Get
        Private Set(ByVal value As String)
            _dependentOnPropertyName = value
        End Set
    End Property

    Public Sub New(ByVal dependentOnPropertyName As String)
        Me.DependentOnPropertyName = dependentOnPropertyName
    End Sub

    ''' <summary>
    ''' Gets a list of properties that are dependent on the given <paramref name="propertyName"/> for their value.
    ''' </summary>
    ''' <param name="type">The class type to look in for dependent properties.</param>
    ''' <param name="propertyName">
    ''' The name of the property on which the returned list of properties are dependent on.</param>
    ''' <returns>
    ''' An array of names of properties that are dependent on the property with the given 
    ''' <paramref name="propertyName"/></returns>
    ''' <remarks>jdb 4/14/2011</remarks>
    Public Shared Function GetDependentPropertyNames(ByVal type As Type, ByVal propertyName As String) As String()
        Static l_cachedProperties As New Dictionary(Of String, String())

        If Not l_cachedProperties.ContainsKey(propertyName) Then
            Dim l_dependentPropertyNames As New List(Of String)
            Dim l_properties = type.GetProperties()
            For Each l_property As Reflection.PropertyInfo In l_properties
                'Iterate through each property in the given type
                Dim l_attributes() As Object = l_property.GetCustomAttributes(GetType(PropertyDependencyAttribute), False)
                For Each l_attribute As PropertyDependencyAttribute In l_attributes
                    'Iterate through each PropertyDependencyAttribute on the property
                    'If the PropertyDependencyAttribute indicates that the property is dependent on the given
                    'propertyName, then add it to the list of dependent properties.
                    If (
                        l_attribute.DependentOnPropertyName = propertyName AndAlso
                        Not l_dependentPropertyNames.Contains(l_property.Name)
                    ) Then l_dependentPropertyNames.Add(l_property.Name)
                Next
            Next

            l_cachedProperties.Add(propertyName, l_dependentPropertyNames.ToArray())
        End If

        Return l_cachedProperties(propertyName)
    End Function

End Class